﻿using Pci9014;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static Nncam;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock;

namespace MicroLED_Detecter
{
    public partial class FormMain : Form
    {
        #region Keithley_2400的单位
        List<string> VOLTrange = new List<string>// 电压的量程
        {
            "200mV","2V","20V","200V"
        };
        List<string> CURRrange = new List<string>// 电流的量程
        {
            "1μA", "10μA","100μA","1mA","10mA","100mA","1A"
        };
        List<string> VOLTMeasureCmpUnit = new List<string>// 限电压的单位
        {
            "mV", "V"
        };
        List<string> CURRMeasureCmpUnit = new List<string>// 限电流的单位
        {
            "μA", "mA", "A"
        };
        #endregion

        public Keithley_2400 keithley = new Keithley_2400(); // Keithley_2400
        public ImageTools ImageTools = new ImageTools();
        public AFG_1000 AFG = new AFG_1000();
        private Nncam cam_ = null;
        public Bitmap bmp_ = null;
        public uint count_ = 0;
        int flag_IsCamConnected = 0;// 相机是否被连接
        int flag_IsPCIConnected = 0;// 控制轴是否被连接
        int flag_IsArrayScan = 0;// 是否正在进行阵列扫描
        int flag_IsContinueArrayScan = 0;// 是否是继续上一次扫描

        //XYR移动平台
        int axis = 0;
        int m_axis = 0;
        int rc = 0;
        int incr = 0;
        int incrtemp = 0;

        // 阵列扫描
        public ArrayScan ArrayScan = new ArrayScan();
        public Thread continueSnapThread = null;
        int rowcount = 0;// 本次阵列扫描的行数
        int columncount = 0;// 本次阵列扫描的列数
        int scaninterrupt_row = 0;
        int scaninterrupt_column = 0;
        bool flag_scaninterrupt = false;

        public FormMain()
        {
            InitializeComponent();
        }
        private void FormMain_Load(object sender, EventArgs e)
        {
            // Keithley
            UpdatePorts();
            cbx_SourceMode.SelectedIndex = 1;
            SetSourceRange(cbx_SourceMode.SelectedIndex);
            cbx_distanceRunUnit.SelectedIndex = 0;

            // AFG
            cbx_AFGWaveShape.SelectedIndex = 0;
            cbx_AFGFrequencyUnit.SelectedIndex = 0;
            cbx_AFGOffsetUnit.SelectedIndex = 0;
            cbx_AFGPhaseUnit.SelectedIndex = 1;

            cbx_AFGWaveShape2.SelectedIndex = 0;
            cbx_AFGFrequencyUnit2.SelectedIndex = 0;
            cbx_AFGOffsetUnit2.SelectedIndex = 0;
            cbx_AFGPhaseUnit2.SelectedIndex = 1;

            // 相机
            btn_takePhotos.Enabled = false;
            btn_whitebalance.Enabled = false;
            numericUpDown_expoTime.Enabled = false;
            trbar_temp.Enabled = false;
            trbar_color.Enabled = false;
            chebx_AutoExpo.Enabled = false;
            cbx_SelectResolution.Enabled = false;
            trbar_temp.SetRange(Nncam.TEMP_MIN, Nncam.TEMP_MAX);
            trbar_color.SetRange(Nncam.TINT_MIN, Nncam.TINT_MAX);

            cbx_Opticalpower.SelectedIndex = 8;
            UpdateWidgetStatus();
        }
        private void OnClosing(object sender, FormClosingEventArgs e) // 关闭窗口
        {
            cam_?.Close();
            cam_ = null;
        }
        private void UpdateWidgetStatus()// 更新控件状态
        {
            int IsKeithleyConnected = 0;
            int IsKeithleyOutput = 0;
            int IsAFGConnected = 0;
            int IsAFGOutput = 0;
            IsKeithleyConnected = keithley.IsConnected();
            IsKeithleyOutput = keithley.IsOutput();
            IsAFGConnected = AFG.IsAFGConnected();
            IsAFGOutput = AFG.IsAFGOutput();


            if (IsKeithleyConnected == 0)
            {
                tssl_IsKeithleyConnected.Text = "Keithley_2400未连接   ";
                tssl_IsKeithleyConnected.ForeColor = Color.Red;
            }
            else
            {
                tssl_IsKeithleyConnected.Text = "Keithley_2400已连接   ";
                tssl_IsKeithleyConnected.ForeColor = Color.Green;
            }

            if (IsKeithleyOutput == 0)
            {
                tssl_IsKeithleyOutput.Text = "Keithley_2400未在输出   ";
                tssl_IsKeithleyOutput.ForeColor = Color.Red;
            }
            else
            {
                tssl_IsKeithleyOutput.Text = "Keithley_2400正在输出   ";
                tssl_IsKeithleyOutput.ForeColor = Color.Green;
            }
            if(IsAFGConnected == 0)
            {
                tssl_IsAFGConnected.Text = "AFG_1000未连接   ";
                tssl_IsAFGConnected.ForeColor = Color.Red;
            }
            else
            {
                tssl_IsAFGConnected.Text = "AFG_1000已连接   ";
                tssl_IsAFGConnected.ForeColor = Color.Green;
            }
            if (IsAFGOutput == 0)
            {
                tssl_IsAFGOutput.Text = "AFG_1000未在输出   ";
                tssl_IsAFGOutput.ForeColor = Color.Red;
            }
            else
            {
                tssl_IsAFGOutput.Text = "AFG_1000正在输出   ";
                tssl_IsAFGOutput.ForeColor = Color.Green;
            }
            if (flag_IsCamConnected == 0)
            {
                tssl_CamConn.Text = "相机未连接   ";
                tssl_CamConn.ForeColor = Color.Red;
                // 加载图片
                Image image = Image.FromFile(@"data\logo\detection.png");
                // 将图片显示在PictureBox上
                pb_Image.Image = image;
            }
            else
            {
                tssl_CamConn.Text = "相机已连接   ";
                tssl_CamConn.ForeColor = Color.Green;
            }
            if(flag_IsPCIConnected == 0)
            {
                tssl_XYRConn.Text = "XYR运动轴未连接   ";
                tssl_XYRConn.ForeColor = Color.Red;
            }
            else
            {
                tssl_XYRConn.Text = "XYR运动轴已连接   ";
                tssl_XYRConn.ForeColor = Color.Green;
            }
            if(flag_IsArrayScan == 0)
            {
                tssl_arrayscan.Text = "未在进行阵列扫描   ";
                tssl_arrayscan.ForeColor = Color.Red;
            }
            else
            {
                tssl_arrayscan.Text = $"正在进行{rowcount}×{columncount}阵列扫描   ";
                tssl_arrayscan.ForeColor = Color.Green;
                tssl_IsInterrupting.Text = "   ";
            }
            if(ArrayScan.IsExistInterruptionRecord() == 0)
            {
                tssl_scanSingle.Text = "   ";
            }
            else
            {
                scaninterrupt_row = ArrayScan.GetScanInterrupt_row();
                scaninterrupt_column = ArrayScan.GetScanInterrupt_column();
                tssl_scanSingle.Text = $"上次扫描完成至第{scaninterrupt_row}×{scaninterrupt_column}个芯片   ";
                tssl_scanSingle.ForeColor = Color.Red;
            }
        }

        #region 信号发生器
        private void SaveAFGParameters(int WaveShape, string Level, string Frequency, int FrequencyUnit, string Offset, int OffsetUnit, string Phase, int PhaseUnit)
        {
            AFG.SaveParameters(WaveShape, Level, Frequency, FrequencyUnit, Offset, OffsetUnit, Phase, PhaseUnit);
        }
        private void SaveAFGParameters2(int WaveShape, string Level, string Frequency, int FrequencyUnit, string Offset, int OffsetUnit, string Phase, int PhaseUnit)
        {
            AFG.SaveParameters2(WaveShape, Level, Frequency, FrequencyUnit, Offset, OffsetUnit, Phase, PhaseUnit);
        }
        private void btn_ConnectAFG_Click(object sender, EventArgs e)// 连接AFG信号发生器
        {
            int ret = AFG.Connect();
            if (ret == 1)
            {
                SaveAFGParameters(cbx_AFGWaveShape.SelectedIndex, tbx_AFGLevel.Text, tbx_AFGFrequency.Text, cbx_AFGFrequencyUnit.SelectedIndex, tbx_AFGOffset.Text, cbx_AFGOffsetUnit.SelectedIndex, tbx_AFGPhase.Text, cbx_AFGPhaseUnit.SelectedIndex);
                SaveAFGParameters2(cbx_AFGWaveShape2.SelectedIndex, tbx_AFGLevel2.Text, tbx_AFGFrequency2.Text, cbx_AFGFrequencyUnit2.SelectedIndex, tbx_AFGOffset2.Text, cbx_AFGOffsetUnit2.SelectedIndex, tbx_AFGPhase2.Text, cbx_AFGPhaseUnit2.SelectedIndex);
            }
            UpdateWidgetStatus();
        }
        private void btn_SaveAFGParameters_Click(object sender, EventArgs e)// 保存AFG参数
        {
            SaveAFGParameters(cbx_AFGWaveShape.SelectedIndex, tbx_AFGLevel.Text, tbx_AFGFrequency.Text, cbx_AFGFrequencyUnit.SelectedIndex, tbx_AFGOffset.Text, cbx_AFGOffsetUnit.SelectedIndex, tbx_AFGPhase.Text, cbx_AFGPhaseUnit.SelectedIndex);
        }
        private void btn_AFGOutput_Click(object sender, EventArgs e)// AFG输出
        {
            AFG.Output1();
            UpdateWidgetStatus();
        }

        private void btn_AFGStopOutput_Click(object sender, EventArgs e)// AFG停止输出
        {
            AFG.StopOutput1();
            UpdateWidgetStatus();
        }

        private void btn_DisconnectAFG_Click(object sender, EventArgs e)// 断开AFG
        {
            AFG.disConnect();
            UpdateWidgetStatus();
        }
        private void btn_SaveAFGParameters2_Click(object sender, EventArgs e)
        {
            SaveAFGParameters2(cbx_AFGWaveShape2.SelectedIndex, tbx_AFGLevel2.Text, tbx_AFGFrequency2.Text, cbx_AFGFrequencyUnit2.SelectedIndex, tbx_AFGOffset2.Text, cbx_AFGOffsetUnit2.SelectedIndex, tbx_AFGPhase2.Text, cbx_AFGPhaseUnit2.SelectedIndex);
        }

        private void btn_AFGOutput2_Click(object sender, EventArgs e)
        {
            AFG.Output2();
            UpdateWidgetStatus();
        }

        private void btn_AFGStopOutput2_Click(object sender, EventArgs e)
        {
            AFG.StopOutput2();
            UpdateWidgetStatus();
        }

        #endregion


        #region Keithley_2400的函数
        private void UpdatePorts()// 更新可用的连接端口
        {
            string[] ports = SerialPort.GetPortNames();// 找到所有可用的端口
            for (int i = 0; i < ports.Length; i++)
            {
                string port = ports[i];
                cbx_portName.Items.Clear();
                cbx_portName.Items.Add(port);// 加载所有可用端口
            }
            if (cbx_portName.Items.Count > 0)// 如果有可用端口，则设第一个为默认端口
                cbx_portName.SelectedIndex = 0;
        }
        private void SetSourceRange(int source_mode)// 导入恒压模式或恒流模式下的输出量程选项
        {
            if (source_mode == 0)// 恒压模式
            {
                cbx_SourceRange.Items.Clear();
                cbx_SourceRange.Items.AddRange(VOLTrange.ToArray());// 把电压的量程选项导入
                cbx_MeasureCmpUnit.Items.Clear();
                cbx_MeasureCmpUnit.Items.AddRange(CURRMeasureCmpUnit.ToArray());// 把限电流的单位导入
                label_SetMeasureCmp.Text = "测量限电流：";
            }
            else if (source_mode == 1)
            {
                cbx_SourceRange.Items.Clear();
                cbx_SourceRange.Items.AddRange(CURRrange.ToArray());// 把电流的量程选项导入
                cbx_MeasureCmpUnit.Items.Clear();
                cbx_MeasureCmpUnit.Items.AddRange(VOLTMeasureCmpUnit.ToArray());// 把限电压的单位导入
                label_SetMeasureCmp.Text = "测量限电压：";
            }
            cbx_SourceRange.SelectedIndex = 0;// 默认输出量程10mV(10μA)            
            tbx_SourceLevelValue.Text = "0";// 默认输出电压(流)的值为0
            cbx_MeasureCmpUnit.SelectedIndex = 0;// 默认限电压(流)的单位是mV(μA)
            tbx_MeasureCmpValue.Text = "1";// 默认限电压(流)的值是1
        }
        private void btn_ConnectKeithley_Click(object sender, EventArgs e)// 连接Keithley
        {
            int ret = 0;
            ret = keithley.Connect(cbx_portName.Text);
            if(ret == 1)
                keithley.SaveParameters(cbx_SourceMode.SelectedIndex, cbx_SourceRange.Text, tbx_SourceLevelValue.Text, tbx_MeasureCmpValue.Text, cbx_MeasureCmpUnit.SelectedIndex);
            UpdateWidgetStatus();
        }

        private void btn_DisconnectKeithley_Click(object sender, EventArgs e)// 断开Keithley
        {
            keithley.Disconnect();
            UpdateWidgetStatus();
            UpdatePorts();
        }

        private void cbx_SourceMode_SelectedIndexChanged(object sender, EventArgs e)// Keithley恒压/恒流模式转换，重新导入输出量程
        {
            SetSourceRange(cbx_SourceMode.SelectedIndex);
        }

        private void cbx_SourceRange_SelectedIndexChanged(object sender, EventArgs e)// Keithley输出量程转换，重新导入输出单位
        {
            string level_unit = null;
            level_unit = keithley.GetRangeUnit(cbx_SourceRange.Text);// 根据选择的量程得到输出单位
            label_SourceLevelUnit.Text = level_unit;
        }
        private void btn_SaveParameters_Click(object sender, EventArgs e)
        {
            keithley.SaveParameters(cbx_SourceMode.SelectedIndex, cbx_SourceRange.Text, tbx_SourceLevelValue.Text, tbx_MeasureCmpValue.Text, cbx_MeasureCmpUnit.SelectedIndex);
        }

        private void btn_Output_Click(object sender, EventArgs e)// Keithley输出
        {
            keithley.Output();
            UpdateWidgetStatus();
        }

        private void btn_StopOutput_Click(object sender, EventArgs e)// Keithley停止输出
        {
            keithley.StopOutput();
            UpdateWidgetStatus();
        }
        #endregion

        #region 相机的函数
        private void OnEventError()
        {
            cam_.Close();
            cam_ = null;
            MessageBox.Show("Generic error.");
        }

        private void OnEventDisconnected()
        {
            cam_.Close();
            cam_ = null;
            MessageBox.Show("Camera disconnect.");
        }
        private void OnEventImage()
        {
            if (bmp_ != null)
            {
                Nncam.FrameInfoV3 info = new Nncam.FrameInfoV3();
                bool bOK = false;
                try
                {
                    BitmapData bmpdata = bmp_.LockBits(new Rectangle(0, 0, bmp_.Width, bmp_.Height), ImageLockMode.ReadWrite, bmp_.PixelFormat);
                    try
                    {
                        bOK = cam_.PullImageV3(bmpdata.Scan0, 0, 24, bmpdata.Stride, out info); // check the return value
                    }
                    finally
                    {
                        bmp_.UnlockBits(bmpdata);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
                if (bOK) pb_Image.Image = bmp_;
            }
        }

        private void OnEventStillImage()
        {
            Nncam.FrameInfoV3 info = new Nncam.FrameInfoV3();
            if (cam_.PullImageV3(IntPtr.Zero, 1, 24, 0, out info))   /* peek the width and height */
            {
                Bitmap sbmp = new Bitmap((int)info.width, (int)info.height, PixelFormat.Format24bppRgb);
                bool bOK = false;
                try
                {
                    BitmapData bmpdata = sbmp.LockBits(new Rectangle(0, 0, sbmp.Width, sbmp.Height), ImageLockMode.WriteOnly, sbmp.PixelFormat);
                    try
                    {
                        bOK = cam_.PullImageV3(bmpdata.Scan0, 1, 24, bmpdata.Stride, out info); // check the return value
                    }
                    finally
                    {
                        sbmp.UnlockBits(bmpdata);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
                if (bOK)
                    sbmp.Save(string.Format("Image_{0}.jpg", ++count_), ImageFormat.Jpeg);
            }
        }
        private void DelegateOnEventCallback(Nncam.eEVENT evt)
        {
            BeginInvoke((Action)(() =>
            {
                if (cam_ != null)
                {
                    switch (evt)
                    {
                        case Nncam.eEVENT.EVENT_ERROR:
                            OnEventError();
                            break;
                        case Nncam.eEVENT.EVENT_DISCONNECTED:
                            OnEventDisconnected();
                            break;
                        case Nncam.eEVENT.EVENT_EXPOSURE:
                            OnEventExposure();
                            break;
                        case Nncam.eEVENT.EVENT_IMAGE:
                            OnEventImage();
                            break;
                        case Nncam.eEVENT.EVENT_STILLIMAGE:
                            OnEventStillImage();
                            break;
                        case Nncam.eEVENT.EVENT_TEMPTINT:
                            OnEventTempTint();
                            break;
                        default:
                            break;
                    }
                }
            }));
        }
        private void OnEventTempTint()
        {
            int nTemp = 0, nTint = 0;
            if (cam_.get_TempTint(out nTemp, out nTint))
            {
                label_temp.Text = nTemp.ToString();
                label_color.Text = nTint.ToString();
                trbar_temp.Value = nTemp;
                trbar_color.Value = nTint;
            }
        }
        private void OnEventExposure()
        {
            uint nTime = 0;
            if (cam_.get_ExpoTime(out nTime))
            {
                numericUpDown_expoTime.Value = (int)nTime;
                label_Expotime.Text = nTime.ToString();
            }
        }
        private void InitExpoTimeRange()
        {
            uint nMin = 0, nMax = 0, nDef = 0;
            if (cam_.get_ExpTimeRange(out nMin, out nMax, out nDef))
                numericUpDown_expoTime.Minimum = (int)nMin;
            numericUpDown_expoTime.Maximum = (int)nMax;
            OnEventExposure();
        }
        private void startDevice(string id) // 启动相机
        {
            cam_ = Nncam.Open(id);
            if (cam_ != null)
            {
                chebx_AutoExpo.Enabled = true;
                cbx_SelectResolution.Enabled = true;
                btn_takePhotos.Enabled = true;
                InitExpoTimeRange();

                if (cam_.MonoMode)
                {
                    trbar_temp.Enabled = false;
                    trbar_color.Enabled = false;
                    btn_whitebalance.Enabled = false;
                }
                else
                {
                    trbar_temp.Enabled = true;
                    trbar_color.Enabled = true;
                    btn_whitebalance.Enabled = true;
                    OnEventTempTint();
                }

                uint resnum = cam_.ResolutionNumber;
                uint eSize = 0;
                if (cam_.get_eSize(out eSize))
                {
                    for (uint i = 0; i < resnum; ++i)
                    {
                        int w = 0, h = 0;
                        if (cam_.get_Resolution(i, out w, out h))
                            cbx_SelectResolution.Items.Add(w.ToString() + "*" + h.ToString());
                    }
                    cbx_SelectResolution.SelectedIndex = (int)eSize;

                    int width = 0, height = 0;
                    if (cam_.get_Size(out width, out height))
                    {
                        bmp_ = new Bitmap(width, height, PixelFormat.Format24bppRgb);
                        if (!cam_.StartPullModeWithCallback(new Nncam.DelegateEventCallback(DelegateOnEventCallback)))
                            MessageBox.Show("Failed to start camera.");
                        else
                        {
                            bool autoexpo = true;
                            cam_.get_AutoExpoEnable(out autoexpo);
                            chebx_AutoExpo.Checked = autoexpo;
                            numericUpDown_expoTime.Enabled = !autoexpo;

                            flag_IsCamConnected = 1;//相机就绪，如果控制轴就绪则阵列扫描可用
                            UpdateWidgetStatus();
                        }
                    }
                }

                timer1.Start();

            }
        }
        private void OnStart(object sender, EventArgs e)// 连接相机
        {
            if (cam_ != null)
                return;

            Nncam.DeviceV2[] arr = Nncam.EnumV2();
            if (arr.Length <= 0)
                MessageBox.Show("No camera found.");
            else if (1 == arr.Length)
                startDevice(arr[0].id);
            else
            {
                ContextMenuStrip ctxmenu = new ContextMenuStrip();
                ctxmenu.ItemClicked += (nsender, ne) =>
                {
                    startDevice((string)(ne.ClickedItem.Tag));
                };
                for (int i = 0; i < arr.Length; ++i)
                    ctxmenu.Items.Add(arr[i].displayname).Tag = arr[i].id;
                ctxmenu.Show(btn_connectCam, 0, 0);
            }
        }

        private void OnTimer1(object sender, EventArgs e)
        {
            if (cam_ != null)
            {
                uint nFrame = 0, nTime = 0, nTotalFrame = 0;
                if (cam_.get_FrameRate(out nFrame, out nTime, out nTotalFrame) && (nTime > 0))
                    label_fps.Text = string.Format("{0}; fps = {1:#.0}", nTotalFrame, ((double)nFrame) * 1000.0 / (double)nTime);
            }
        }

        private void OnSnap(object sender, EventArgs e) // 拍摄图片
        {
            if (cam_ != null)
            {
                if (cam_.StillResolutionNumber <= 0)
                    bmp_?.Save(string.Format("Image_{0}.jpg", ++count_), ImageFormat.Jpeg);
                else
                {
                    ContextMenuStrip ctxmenu = new ContextMenuStrip();
                    ctxmenu.ItemClicked += (nsender, ne) =>
                    {
                        uint k = (uint)(ne.ClickedItem.Tag); //unbox
                        if (k < cam_.StillResolutionNumber)
                            cam_.Snap(k);
                    };
                    for (uint i = 0; i < cam_.ResolutionNumber; ++i)
                    {
                        int w = 0, h = 0;
                        cam_.get_Resolution(i, out w, out h);
                        ctxmenu.Items.Add(string.Format("{0} * {1}", w, h)).Tag = i; // box
                    }
                    ctxmenu.Show(btn_takePhotos, 0, 0);
                }
            }
        }

        private void OnSelectResolution(object sender, EventArgs e) // 更改图像分辨率
        {
            if (cam_ != null)
            {
                uint eSize = 0;
                if (cam_.get_eSize(out eSize))
                {
                    if (eSize != cbx_SelectResolution.SelectedIndex)
                    {
                        cam_.Stop();
                        cam_.put_eSize((uint)cbx_SelectResolution.SelectedIndex);

                        InitExpoTimeRange();
                        OnEventTempTint();

                        int width = 0, height = 0;
                        if (cam_.get_Size(out width, out height))
                        {
                            bmp_ = new Bitmap(width, height, PixelFormat.Format24bppRgb);
                            cam_.StartPullModeWithCallback(new Nncam.DelegateEventCallback(DelegateOnEventCallback));
                        }
                    }
                }
            }
        }

        private void chebx_AutoExpo_CheckedChanged(object sender, EventArgs e) // 设置自动曝光时间
        {
            cam_?.put_AutoExpoEnable(chebx_AutoExpo.Checked);
            numericUpDown_expoTime.Enabled = !chebx_AutoExpo.Checked;
        }

        private void OnExpoValueChange(object sender, EventArgs e) // 手动设置曝光时间
        {
            if ((!chebx_AutoExpo.Checked) && (cam_ != null))
            {
                uint n = (uint)numericUpDown_expoTime.Value;
                cam_.put_ExpoTime(n);
                label_Expotime.Text = n.ToString();
            }
        }
        private void OnWhiteBalanceOnce(object sender, EventArgs e) // 设置白平衡
        {
            cam_?.AwbOnce();
        }
        private void OnTempTintChanged(object sender, EventArgs e)// 设置温度和色彩
        {
            cam_?.put_TempTint(trbar_temp.Value, trbar_color.Value);
            label_temp.Text = trbar_temp.Value.ToString();
            label_color.Text = trbar_color.Value.ToString();
        }
        #endregion


        private void Initialize_X_axis()// 初始化X轴：调整X轴的限位和运动参数，具体参数需要调试确定
        {
            CPCI9014.p9014_axis_set_parameter(0, 1000, 1);
            CPCI9014.p9014_axis_set_parameter(0, 1007, 1);
            CPCI9014.p9014_axis_set_parameter(0, 1008, 1);
            CPCI9014.p9014_axis_set_parameter(0, 1009, 1);
            CPCI9014.p9014_axis_set_parameter(0, 1010, 1);
            CPCI9014.p9014_axis_set_parameter(0, 1014, 1);
            CPCI9014.p9014_set_s_profile(0, 0, 0.3, 0, 0, 0);
        }
        private void Initialize_Y_axis()// 初始化Y轴：调整X轴的限位和运动参数，具体参数需要调试确定
        {
            CPCI9014.p9014_axis_set_parameter(1, 1000, 1);
            CPCI9014.p9014_axis_set_parameter(1, 1007, 1);
            CPCI9014.p9014_axis_set_parameter(1, 1008, 1);
            CPCI9014.p9014_axis_set_parameter(1, 1009, 1);
            CPCI9014.p9014_axis_set_parameter(1, 1010, 1);
            CPCI9014.p9014_axis_set_parameter(1, 1014, 1);
            CPCI9014.p9014_set_s_profile(1, 0, 0.3, 0, 0, 0);
        }
        private void Initialize_R_axis()// 初始化R轴：调整X轴的限位和运动参数，具体参数需要调试确定
        {
            CPCI9014.p9014_axis_set_parameter(2, 1000, 1);
            CPCI9014.p9014_axis_set_parameter(2, 1007, 1);
            CPCI9014.p9014_axis_set_parameter(2, 1008, 1);
            CPCI9014.p9014_axis_set_parameter(2, 1009, 1);
            CPCI9014.p9014_axis_set_parameter(2, 1010, 0);
            CPCI9014.p9014_axis_set_parameter(2, 1014, 1);
            CPCI9014.p9014_set_s_profile(2, 0, 0.3, 0, 0, 0);
        }

        #region PCI轴的函数
        private void btn_connectPCI_Click(object sender, EventArgs e)//寻找控制卡，确定控制轴
        {
            if(flag_IsPCIConnected == 1)
                return;

            int cardCount = 0;
            int[] cardIDs = new int[16];
            rc = CPCI9014.p9014_initial(ref cardCount, cardIDs);
            if (rc != 0)
            {
                MessageBox.Show("初始化PCI-9014失败");
                Application.Exit();
            }
            if (cardCount < 1)
            {
                MessageBox.Show("未找到PCI-9014设备");
            }
            else
            {
                for (int i = 0; i < cardCount; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        axis = cardIDs[i] * 4 + j;
                        cbx_axis.Items.Add(axis.ToString());
                    }
                }
                //调整各轴的限位和运动参数，具体参数需要调试确定
                Initialize_X_axis();
                Initialize_Y_axis();
                Initialize_R_axis();

                MessageBox.Show("控制轴连接成功");
                //cbx_axis.Enabled = true;
                //gb_distanceRun.Enabled = true;
                //btn_stoprun.Enabled = true;
                flag_IsPCIConnected = 1;//控制轴准备就绪，如果相机也就绪则阵列扫描可
                UpdateWidgetStatus();
            }
        }

        private void cbx_axis_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbx_axis.SelectedIndex == 0)
                m_axis = 0;
            else if (cbx_axis.SelectedIndex == 1)
                m_axis = 1;
            else if (cbx_axis.SelectedIndex == 2)
                m_axis = 2;
            else
                MessageBox.Show("未找到该控制轴");
        }

        private void btn_ForwardRun_Click(object sender, EventArgs e)//正向运行
        {
            if (flag_IsPCIConnected == 0)
                return;
            CPCI9014.p9014_vmove(m_axis, 1, 1);
        }

        private void btn_ReverseRun_Click(object sender, EventArgs e)//反向运行
        {
            if (flag_IsPCIConnected == 0)
                return;
            CPCI9014.p9014_vmove(m_axis, 0, 1);
        }
        private void btn_stoprun_Click(object sender, EventArgs e)//停止运行
        {
            if (flag_IsPCIConnected == 0)
                return;
            CPCI9014.p9014_stop(0, 1);
            CPCI9014.p9014_stop(1, 1);
            CPCI9014.p9014_stop(2, 1);
        }
        
        private void tbx_distance_TextChanged(object sender, EventArgs e)
        {
            if (cbx_distanceRunUnit.SelectedIndex == 0)
            {
                if (!string.IsNullOrEmpty(tbx_distance.Text))
                {
                    if (tbx_distance.Text == "-")//消除输入负号报错的影响
                    {
                        incr = 0;
                    }
                    else if (tbx_distance.Text.StartsWith("-"))//消除开头输入负号报错的影响
                    {
                        string distance = tbx_distance.Text.Substring(1);
                        incrtemp = int.Parse(distance);//测算出脉冲计数1=移动2μm
                        if (incrtemp % 2 == 1) //消除脉冲计数只能为整数的影响
                        {
                            incr = (incrtemp + 1) / 2;
                        }
                        else { incr = incrtemp / 2; }
                    }
                    else
                    {
                        incrtemp = int.Parse(tbx_distance.Text);
                        if (incrtemp % 2 == 1)
                        {
                            incr = (incrtemp + 1) / 2;
                        }
                        else { incr = incrtemp / 2; }
                    }
                }
                else
                {
                    incr = 0;
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(tbx_distance.Text))
                {
                    if (tbx_distance.Text == "-")//消除输入负号报错的影响
                    {
                        incr = 0;
                    }
                    else if (tbx_distance.Text.StartsWith("-"))//消除开头输入负号报错的影响
                    {
                        string distance = tbx_distance.Text.Substring(1);
                        incr = int.Parse(distance);//测算出脉冲计数
                    }
                    else
                    {
                        incr = int.Parse(tbx_distance.Text);
                    }
                }
                else
                {
                    incr = 0;
                }
            }
        }

        private void btn_YFdistanceRun_Click(object sender, EventArgs e)
        {
            if (flag_IsPCIConnected == 0)
                return;
            if(tbx_distance.Text.StartsWith("-"))
                CPCI9014.p9014_axis_incr_move(1, incr);
            else
                CPCI9014.p9014_axis_incr_move(1, -incr);
        }

        private void btn_XRdistanceRun_Click(object sender, EventArgs e)
        {
            if (flag_IsPCIConnected == 0)
                return;
            if (tbx_distance.Text.StartsWith("-"))
                CPCI9014.p9014_axis_incr_move(0, incr);
            else
                CPCI9014.p9014_axis_incr_move(0, -incr);
        }

        private void btn_XFdistanceRun_Click(object sender, EventArgs e)
        {
            if (flag_IsPCIConnected == 0)
                return;
            if (tbx_distance.Text.StartsWith("-"))
                CPCI9014.p9014_axis_incr_move(0, -incr);
            else
                CPCI9014.p9014_axis_incr_move(0, incr);
        }

        private void btn_YRdistanceRun_Click(object sender, EventArgs e)
        {
            if (flag_IsPCIConnected == 0)
                return;
            if (tbx_distance.Text.StartsWith("-"))
                CPCI9014.p9014_axis_incr_move(1, -incr);
            else
                CPCI9014.p9014_axis_incr_move(1, incr);
        }

        private void btn_RFdistanceRun_Click(object sender, EventArgs e)
        {
            if (flag_IsPCIConnected == 0)
                return;
            if (tbx_distance.Text.StartsWith("-"))
                CPCI9014.p9014_axis_incr_move(2, -incr);
            else
                CPCI9014.p9014_axis_incr_move(2, incr);
        }

        private void btn_RRdistanceRun_Click(object sender, EventArgs e)
        {
            if (flag_IsPCIConnected == 0)
                return;
            if (tbx_distance.Text.StartsWith("-"))
                CPCI9014.p9014_axis_incr_move(2, incr);
            else
                CPCI9014.p9014_axis_incr_move(2, -incr);
        }

        #endregion

        #region 图像工具的函数

        private void btn_Opticalpower_Click(object sender, EventArgs e)
        {
            label_Opticalpower.Text = "光学倍率：1X " + cbx_Opticalpower.Text + " 20X";
            ImageTools.Confirm_Opticalpower(btn_ShoworCloPositionline.Text, btn_ShoworCloTickmaks.Text, label_Opticalpower.Text);
        }

        private void btn_ShoworCloPositionline_Click(object sender, EventArgs e)
        {
            if(flag_IsCamConnected == 0)
                return;

            int ret = 0;
            ret = ImageTools.ShoworCloPositionline(label_Opticalpower.Text);
            if(ret == 0)
                btn_ShoworCloPositionline.Text = "隐藏";
            else
                btn_ShoworCloPositionline.Text = "显示";
        }

        private void btn_ShoworCloTickmaks_Click(object sender, EventArgs e)
        {
            if (flag_IsCamConnected == 0)
                return;

            int ret = 0;
            ret = ImageTools.ShoworCloTickmaks(label_Opticalpower.Text);
            if (ret == 0)
                btn_ShoworCloTickmaks.Text = "隐藏";
            else
                btn_ShoworCloTickmaks.Text = "显示";
        }

        private void pb_Image_Paint(object sender, PaintEventArgs e)
        {
            ImageTools.Paint(e);
        }

        #endregion

        #region 阵列扫描的函数
        private void btn_scanGetphoto_Click(object sender, EventArgs e) // 开始阵列扫描
        {
            if (flag_IsCamConnected == 0 || flag_IsPCIConnected == 0)
                return;
            if (flag_IsArrayScan == 1)
                return;

            if (int.TryParse(tbx_scanrow.Text, out int parsedNumber1) && int.TryParse(tbx_scancolumn.Text, out int parsedNumber2)) // 尝试将文本转换为整数
            {
                rowcount = parsedNumber1; // 将转换后的整数赋值给变量
                columncount = parsedNumber2; // 将转换后的整数赋值给变量
            }    
            else
            {
                MessageBox.Show("输入的不是有效的整数！");
                return;
            }

            flag_IsArrayScan = 1;// 正在扫描
            flag_IsContinueArrayScan = 0;// 非继续上次扫描
            flag_scaninterrupt = false;// 不需要中断
            UpdateWidgetStatus();

            continueSnapThread = new Thread(continueSnap);
            continueSnapThread.Start();           
        }       

        private void btn_scanArryContinue_Click(object sender, EventArgs e)// 继续上次扫描
        {
            int ret = ArrayScan.IsExistInterruptionRecord();

            if (flag_IsCamConnected == 0 || flag_IsPCIConnected == 0)
                return;
            if (flag_IsArrayScan == 1)
                return;
            if (ret == 0)
                return;

            rowcount = ArrayScan.GetRowcount();
            columncount = ArrayScan.GetColumncount();

            flag_IsArrayScan = 1;// 正在扫描
            flag_IsContinueArrayScan = 1;// 是继续上次扫描
            flag_scaninterrupt = false;// 不需要中断
            UpdateWidgetStatus();

            continueSnapThread = new Thread(continueSnap);
            continueSnapThread.Start();
        }

        private void btn_scaninterrupt_Click(object sender, EventArgs e) // 中断扫描
        {
            if (flag_IsArrayScan == 0)
                return;

            tssl_IsInterrupting.Text = "正在中断扫描，请稍等...   ";
            tssl_IsInterrupting.ForeColor = Color.Green;
            flag_scaninterrupt = true;
        }

        private void continueSnap()
        {
            int row = 1;
            int column = 1;
            int new_row = 1;
            int new_column = 1;
            int flag_IsFinishedOneRow = 0;
            string targetPath = @"data\scanImg";// 获取扫描图片存储文件夹的路径
            string foldername = null;
            string interrupt_filePath = Path.Combine(targetPath, "interrupt.txt");// 中断信息文件路径
            string data_modified = null;// 中断信息文件里面的信息

            int X_scanincr_one = int.Parse(tbx_scanincr_oneX.Text);// X方向上的扫描间隔
            int Y_scanincr_one = int.Parse(tbx_scanincr_oneY.Text);// Y方向上的扫描间隔
            int X_scanincr_one_true = 0;
            int columntemp = 0;// 因为是Z字型阵列扫描，所以每一行的扫描顺序相反（即从左往右扫和从右往左扫切换），所以创建一个临时变量方便扫描 
            int feedback_dx = 0;
            int feedback_dy = 0;

            // 是否新扫描或者继续上次扫描
            if (flag_IsContinueArrayScan == 1)
            {
                // 如果继续上次扫描，则搜寻上次中断信息
                scaninterrupt_row = ArrayScan.GetScanInterrupt_row();
                scaninterrupt_column = ArrayScan.GetScanInterrupt_column();
                new_row = ArrayScan.GetNewRoworColumn(scaninterrupt_row, scaninterrupt_column, columncount, 0);
                new_column = ArrayScan.GetNewRoworColumn(scaninterrupt_row, scaninterrupt_column, columncount, 1);
                foldername = ArrayScan.GetInterruptionFoldername();
            }
            else
            {
                // 创建本次扫描的信息和图片储存文件                
                foldername = ArrayScan.NewScan_CreateFolder(rowcount, columncount);// yyyy MM dd HH mm ss                         
            }
            string folderPath = Path.Combine(targetPath, foldername);// 已创建    

            // 初始化X/Y轴参数
            Initialize_X_axis();
            Initialize_Y_axis();
            cam_.Snap(0);// 设置相机拍摄的图片的分辨率为第一个分辨率           

            for(row = new_row; row <= rowcount; row++)//阵列扫描
            {
                if (flag_IsFinishedOneRow >= 1)
                    new_column = 1;
                for (column = new_column; column <= columncount; column++)
                {
                    // 正在扫描第row行，第columntemp列的芯片
                    if (row % 2 == 0)
                    {
                        columntemp = columncount + 1 - column;
                        X_scanincr_one_true = -X_scanincr_one;
                    }
                    else
                    {
                        columntemp = column;
                        X_scanincr_one_true = X_scanincr_one;
                    }

                    string TempfilePath = @"data\Tempimg\image_temp.jpg";//反馈用照片储存位置
                    string need_detection_filePath = @"data\Tempimg\image_undetected.jpg";//检测用照片储存位置
                    string filePath = Path.Combine(folderPath, $"Image_{row}_{columntemp}.jpg"); // 检测好的芯片图像保存位置
                    string txt_filePath = Path.Combine(folderPath, $"Image_{row}_{columntemp}.txt");// 检测结果保存位置                   
                   
                    Invoke((Action)(() =>
                    {
                        bmp_?.Save(TempfilePath, ImageFormat.Jpeg);// 将照片以 JPEG 格式保存到指定路径（反馈用照片）
                    }));
                    if (ArrayScan.GetPythonFeedback(0) == 6)
                        return;
                    feedback_dx = ArrayScan.GetPythonFeedback(0);
                    feedback_dy = ArrayScan.GetPythonFeedback(1);
                    CPCI9014.p9014_axis_incr_move(0, feedback_dx);//dx根据反馈通道2调整水平位置
                    Thread.Sleep(1000);
                    CPCI9014.p9014_axis_incr_move(1, feedback_dy);//dy根据反馈通道1调整竖直位置
                    Thread.Sleep(1000);

                    //反馈调整好后再拍照检测            
                    Invoke((Action)(() =>
                    {
                        bmp_?.Save(need_detection_filePath, ImageFormat.Jpeg);// 将照片以 JPEG 格式保存到指定路径(检测用照片)
                    }));

                    int ret = ArrayScan.RunPythonDetection();// 运行python检测程序X_scanincr_one
                    if (ret == 6)
                        return;

                    // 将检测好的图片和检测信息复制到存储文件夹中
                    string sourceFilePath = @"data\Tempimg\image_detected.jpg";
                    string txt_sourceFilePath = @"data\Tempimg\detectionResult.txt";
                    File.Copy(sourceFilePath, filePath, true);
                    File.Copy(txt_sourceFilePath, txt_filePath, true);

                    Invoke((Action)(() =>
                    {
                        tssl_scanSingle.Text = $"已扫描完成至第{row}×{columntemp}个芯片   ";
                        tssl_scanSingle.ForeColor = Color.Green;
                    }));

                    if (column < columncount)// 扫描至该行最后一个芯片则不运动
                    {
                        CPCI9014.p9014_axis_incr_move(0, X_scanincr_one_true);
                        Thread.Sleep(1000);
                        if(tbx_scanincr_oneYcompensate.Text != "0")
                        {
                            CPCI9014.p9014_axis_incr_move(0, int.Parse(tbx_scanincr_oneYcompensate.Text));
                            Thread.Sleep(1000);
                        }

                        if (flag_scaninterrupt == true) // 中断扫描的处理，不会在该行的最后一列中断
                        {
                            scaninterrupt_row = row;
                            scaninterrupt_column = columntemp;
                            data_modified = scaninterrupt_row.ToString() + " " + scaninterrupt_column.ToString() + "," + foldername + "," + rowcount.ToString() + " " + columncount.ToString();
                            File.WriteAllText(interrupt_filePath, data_modified);

                            flag_IsArrayScan = 0;
                            flag_IsContinueArrayScan = 0;
                            flag_scaninterrupt = false;

                            Invoke((Action)(() =>
                            {
                                UpdateWidgetStatus();
                                tssl_IsInterrupting.Text = "   ";
                            }));
                            
                            return;
                        }
                    }
                    flag_IsFinishedOneRow++;
                }

                if (row < rowcount)// 扫描至最后一个芯片则不运动
                {
                    CPCI9014.p9014_axis_incr_move(1, Y_scanincr_one);//到下一列
                    Thread.Sleep(1000);
                    if(tbx_scanincr_oneXcompensate.Text != "0")
                    {
                        CPCI9014.p9014_axis_incr_move(1, int.Parse(tbx_scanincr_oneXcompensate.Text));
                        Thread.Sleep(1000);
                    }
                }

            }

            MessageBox.Show("扫描完成");                  

            scaninterrupt_row = 0;
            scaninterrupt_column = 0;
            data_modified = scaninterrupt_row.ToString() + " " + scaninterrupt_column.ToString() + "," + foldername + "," + rowcount.ToString() + " " + columncount.ToString();
            File.WriteAllText(interrupt_filePath, data_modified);

            flag_IsArrayScan = 0;
            flag_IsContinueArrayScan = 0;
            flag_scaninterrupt = false;

            Invoke((Action)(() =>
            {
                tssl_IsInterrupting.Text = "   ";
                UpdateWidgetStatus();
            }));            
        }

        private void linkLabel_scanResult_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            FormScanResult formScanResult = new FormScanResult();
            formScanResult.Owner = this;
            formScanResult.Show();
            Toggletsb_Img(false);//只能打开一个FormScanResult
        }

        private void tsb_ScanResult_Click(object sender, EventArgs e)
        {
            FormScanResult formScanResult = new FormScanResult();
            formScanResult.Owner = this;
            formScanResult.Show();
            Toggletsb_Img(false);//只能打开一个FormScanResult
        }
        #endregion

        public void Toggletsb_Img(bool enabled)//只能打开一个FormScanResult
        {
            linkLabel_scanResult.Enabled = enabled;
            tsb_ScanResult.Enabled = enabled;
        }

        public void Toggletsb_Spectrometer(bool enabled)//只能打开一个FormSpectrometer
        {
            tsb_Spectrometer.Enabled = enabled;
        }

        private void tsb_Spectrometer_Click(object sender, EventArgs e)
        {
            FormSpectrometer formSpectrometer = new FormSpectrometer();
            formSpectrometer.Owner = this;
            formSpectrometer.Show();
            Toggletsb_Spectrometer(false);//只能打开一个FormSpectrometer
        }

        private void tsb_about_Click(object sender, EventArgs e)
        {
            MessageBox.Show("MicroLED检测系统V1.0\n版本更新时间：2024.05.14", "版本信息", 0, MessageBoxIcon.Information);
        }

        private void tsb_ImageDetect_Click(object sender, EventArgs e)// 图像检测界面
        {
            string yolov5_detectWindow_path = @"yolov5_detectWindow\yolov5_detectWindow.exe"; // 要运行的exe程序
            Process[] processes = Process.GetProcessesByName("yolov5_detectWindow");// 检查是否已经有相同名称的进程在运行，确保只运行一个exe
            if (processes.Length > 0)
            {
                MessageBox.Show("yolov5_detectWindow.exe已在运行。");
            }
            else
            {
                Process process_Channel3 = new Process();
                process_Channel3.StartInfo.FileName = yolov5_detectWindow_path;
                try
                {
                    process_Channel3.Start();
                    //process_Channel3.WaitForExit(); // 等待进程执行完成
                    //MessageBox.Show("程序结束");
                }
                catch (Exception ex)
                {
                    MessageBox.Show("无法执行python程序：" + ex.Message);
                }
            }
        }
    }
}
